//
//  TableView.m
//  iCodeMacRun
//
//  Created by Andrew Barry on 30/03/09.
//  Copyright 2009 Barry Computer Services. All rights reserved.
//

#import "TableView.h"
#import "WrappedJsval.h"

@implementation TableView

- (id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
	return self;
}

-(void)awakeFromDefn: (jsvalue) defn {
	BOOL outlineView;
	
	NSString *ctlType = jsgetstring(_cx, defn, 0, "type", @"");

	rootCache = [NSMutableDictionary new];

	if ([ctlType isEqualToString:@"outlineview"]) {
		tbl = [[NSOutlineView alloc] init];
		outlineView = YES;
	} else {
		tbl = [[NSTableView alloc] init];
		outlineView = NO;
	}
	
	NSString *columns = jsgetstring(_cx, defn, 0, "columns", nil);
	if (!columns)
		columns = @"";
	
//	[tbl setAutoresizingMask:NSViewWidthSizable];
	[tbl setAllowsColumnResizing: jsgetbool(_cx, defn, 0, "columnResizing", NO)];
	[tbl setAllowsColumnReordering: jsgetbool(_cx, defn, 0, "columnReordering", NO)];
	[tbl setAllowsMultipleSelection: jsgetbool(_cx, defn, 0, "multipleSelection", NO)];
	[tbl setAllowsEmptySelection: jsgetbool(_cx, defn, 0, "emptySelection", NO)];
	
	NSArray *cols = [columns componentsSeparatedByString: @","];
	for (int idx = 0; idx < [cols count]; idx++) {
		NSString *name = [cols objectAtIndex:idx];
		NSTableColumn *col = [[NSTableColumn alloc] initWithIdentifier:[NSNumber numberWithInt:idx]];
		[[col headerCell] setStringValue:name];
		[col setEditable:NO];
		[col setMaxWidth:2000];
		
		[tbl addTableColumn: col];
		
		if (idx == 0 && outlineView)
			[(NSOutlineView *) tbl setOutlineTableColumn: col];
	}
	
	[tbl setDelegate:self];
	[tbl setDoubleAction:@selector(tableDoubleClick:)];
	[tbl setTarget:self];
	
	[tbl setColumnAutoresizingStyle:NSTableViewUniformColumnAutoresizingStyle];
	[self setAutoresizesSubviews:YES];
	[self setDocumentView:tbl];

	if (!jsgetbool(_cx, defn, 0, "visibleHeader", NO)) {
		[tbl setHeaderView:nil];
	}

	[self setBorderType:NSBezelBorder];
	[self setHasHorizontalScroller:outlineView];
	[self setHasVerticalScroller:YES];
    [self setVerticalLineScroll:[tbl rowHeight]];

	[self setAutohidesScrollers:YES];
	[self setAutohidesScrollers:NO];
}

-(void)awake {
	[tbl setDataSource:self];
	[tbl sizeToFit];
}

-(void) setObject: (jsvalue)o withTarget: (jsvalue) targ withContext: (jscontext *) cx {
	jsaddroot(cx, &obj);
	jsaddroot(cx, &target);
	obj = o;
	target = targ;
	_cx = cx;
}

-(void)reloadData {
	[tbl reloadData];
}

-(void) tableDoubleClick: (id) sender {
	jscontext *cx = _cx;
	jsvalue oldEvent = JSVAL_VOID;
	
	int row = [tbl clickedRow];
	if (row < 0)
		return;
	
	jsaddroot(_cx, &oldEvent);
	
	oldEvent = _cx->slots[GLOBAL_EVENT];
	_cx->slots[GLOBAL_EVENT] = jsnewobject(_cx);
	
	jsset(cx, cx->slots[GLOBAL_EVENT], 0, "row", jsnumi(cx, row));

	jsvalue fn = jsget(cx, obj, 0, "DoubleClick");
	if (fn && JSVAL_IS_OBJECT(fn)) {
		jsinvoke(cx, fn, target, nil, 0);
	}

	cx->slots[GLOBAL_EVENT] = oldEvent;
	jsremoveroot(_cx, &oldEvent);
}

- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView {
	jscontext *cx = _cx;
	
	[rootCache removeAllObjects];
	int count = 0;
	jsvalue rv = jsinvokename(cx, obj, "_RowCount", nil, 0);
	jsaddroot(cx, &rv);
	count = jsasint(cx, rv);
	jsremoveroot(cx, &rv);

	return count;
}

- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex {
	jscontext *cx = _cx;
	
	id v = [rootCache objectForKey:[NSNumber numberWithInt:rowIndex]];
	if (!v) {
		jsvalue oldEvent = JSVAL_VOID, rv = JSVAL_VOID;
		
		jsaddroot(cx, &oldEvent);
		oldEvent = cx->slots[GLOBAL_EVENT];
		jsaddroot(cx, &rv);
		
		cx->slots[GLOBAL_EVENT] = jsnewobject(cx);
		
		jsset(cx, cx->slots[GLOBAL_EVENT], 0, "row", INT_TO_JSVAL(rowIndex));
		//	jsset(cx, cx->event, 0, "column", INT_TO_JSVAL([[aTableColumn identifier] intValue]));
		
		rv = jsinvokename(cx, obj, "_Row", nil, 0);
		
		cx->slots[GLOBAL_EVENT] = oldEvent;
		jsremoveroot(cx, &oldEvent);

		if (rv && JSVAL_IS_OBJECT(rv)) {
			v = [WrappedJsval wrap:rv withContext:cx];
		} else {
			v = [jsasstrRetain(cx, rv) autorelease];
		}
		jsremoveroot(cx, &rv);
		
		[rootCache setObject:v forKey:[NSNumber numberWithInt:rowIndex]];
	}

	NSString *str = v;
	return v;
}

- (void)tableViewSelectionDidChange:(NSNotification *)aNotification {
	jsinvokename(_cx, obj, "SelectionChanged", nil, 0);
}

- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
	jscontext *cx = _cx;
	jsvalue oldEvent = JSVAL_VOID, rv = JSVAL_VOID;
	id v;
	
	NSMutableDictionary *parentCache;
	jsaddroot(cx, &rv);

	if (!item) {
		v = [rootCache objectForKey:[NSNumber numberWithInt:index]];
		if (v) {
			return v;
		}

		parentCache = rootCache;
		
		jsaddroot(cx, &oldEvent);
		oldEvent = cx->slots[GLOBAL_EVENT];
		
		cx->slots[GLOBAL_EVENT] = jsnewobject(cx);
		
		jsset(cx, cx->slots[GLOBAL_EVENT], 0, "row", INT_TO_JSVAL(index));
		
		rv = jsinvokename(cx, obj, "_Row", nil, 0);
		cx->slots[GLOBAL_EVENT] = oldEvent;
		jsremoveroot(cx, &oldEvent);

	} else {
		NSMutableDictionary *itemCache = [rootCache objectForKey: item];
		if (!itemCache) {
			itemCache = [[NSMutableDictionary new] autorelease];
			[rootCache setObject:itemCache forKey:item];
		}
		v = [itemCache objectForKey:[NSNumber numberWithInt:index]];
		if (v) {
			return v;
		}
		
		parentCache = itemCache;

		WrappedJsval *jsval = item;
		jsvalue params[2];
		
		params[0] = jsval->val;
		params[1] = jsnumi(cx, index);
		
		jsaddrootmulti(cx, params, 2);
		rv = jsinvokename(cx, obj, "_GetSubItem", params, 2);
		jsremoveroot(cx, params);
	}
	
	if (rv && JSVAL_IS_OBJECT(rv)) {
		v = [WrappedJsval wrap:rv withContext:cx];
	} else {
		v = [jsasstrRetain(cx, rv) autorelease];
	}
	
	[parentCache setObject:v forKey:[NSNumber numberWithInt:index]];
	
	jsremoveroot(cx, &rv);
	return v;
	
}

- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
	if ([item isKindOfClass:[WrappedJsval class]])
		return YES;
	return NO;
}

- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
	if (!item)
		[rootCache removeAllObjects];
	jscontext *cx = _cx;
	int count = 0;

	if (!item) {
		jsvalue rv = jsinvokename(cx, obj, "_RowCount", nil, 0);
		jsaddroot(cx, &rv);
		count = jsasint(cx, rv);
		jsremoveroot(cx, &rv);
	} else {
		WrappedJsval *jsval = item;
		jsvalue rv = jsinvokename(cx, obj, "_GetSubCount", &jsval->val, 1);
		jsaddroot(cx, &rv);
		count = jsasint(cx, rv);
		jsremoveroot(cx, &rv);
	}
	
	return count;
}

- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
	if ([item isKindOfClass:[WrappedJsval class]]) {
		WrappedJsval *jsval = item;
		jsvalue rv = jsinvokename(_cx, obj, "_GetItemDesc", &jsval->val, 1);
		return [jsasstrRetain(_cx, rv) autorelease];
	}
	return item;
}

@end
